package com.changgou.seckill.timer;

import com.changgou.seckill.dao.SeckillGoodsMapper;
import com.changgou.seckill.pojo.SeckillGoods;
import com.changgou.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @Author tang.qingbo
 * @Date 2020/9/8 22:57
 * @Version 1.0
 */
@Component
public class SeckillGoodsPushTask {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    /**
     * 每30秒执行一次该定时任务,将符合参与秒杀的商品放入redis
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void loadGoodsPushRedis() {
        //获取当前时间对应的5个时间段,每隔2小时
        List<Date> dateMenus = DateUtil.getDateMenus();
        for (Date dateMenu : dateMenus) {
            //将当前日期转换为指定格式 例: 2020090822
            String stringDate = DateUtil.data2str(dateMenu, DateUtil.PATTERN_YYYYMMDDHH);

            //获取开始时间
            String startTime = DateUtil.data2str(dateMenu, DateUtil.PATTERN_YYYY_MM_DDHHMMSS);
            String endTime = DateUtil.data2str(DateUtil.addDateHour(dateMenu, 2), DateUtil.PATTERN_YYYY_MM_DDHHMMSS);

            /**
             * 在当前时间段内符合条件的商品放入redis
             *      1. 审核通过
             *      2. 剩余库存数 > 0
             *      3. 开始时间 >= 活动开始时间 && 结束时间 <= 活动开始时间 + 2小时
             */
            Example example = new Example(SeckillGoods.class);
            Example.Criteria criteria = example.createCriteria();
            //审核通过
            criteria.andEqualTo("status", "1");
            //剩余库存 > 0
            criteria.andGreaterThan("stockCount", 0);
            //开始时间 >= 活动开始时间
            criteria.andGreaterThanOrEqualTo("startTime", startTime);
            //结束时间 < 活动开始时间 + 2小时
            criteria.andLessThanOrEqualTo("endTime", endTime);
            //获取redis中所有的key
            Set keys = redisTemplate.boundHashOps("SeckillGoods_" + stringDate).keys();
            if (keys != null && keys.size() > 0) {
                //说明redis中已经存有该数据,不需要重复存储
                criteria.andNotIn("id", keys);
            }
            //执行查询  == 得到符合当前时间段条件的商品数据
            List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectByExample(example);

            if (seckillGoods != null) {
                //循环放入redis
                for (SeckillGoods seckillGood : seckillGoods) {
                    //当前时间段的商品信息
                    redisTemplate.boundHashOps("SeckillGoods_" + stringDate).put(seckillGood.getId(), seckillGood);
                    //将当前商品的id根据商品的个数放置到redis的队列中去,防止超卖,有多少个商品,就在redis的该队列中放多少数据
                    String[] ids = pushIds(seckillGood.getStockCount(), seckillGood.getId());
                    //放入队列 .leftPush总队列的左边存入数据
                    redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillGood.getId()).leftPushAll(ids);
                    //把每个商品对应的总数,单独再放置到一个队列 ======= 自增计数器
                    redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillGood.getId(), seckillGood.getStockCount());
                }
            }
        }
    }

    /**
     * 将指定商品id,根据个数放入string[]数组中
     * 相当于给seckillGoodsId复制了seckillGoodsCount份,组成了id数组
     * @param seckillGoodsCount 商品的个数
     * @param seckillGoodsId 商品的id
     * @return
     */
    private String[] pushIds(Integer seckillGoodsCount,String seckillGoodsId) {
        String[] ids = new String[seckillGoodsCount];
        for (int i = 0; i < ids.length; i++) {
            ids[i] = seckillGoodsId;
        }
        return ids;
    }
}
